#include <jni.h>
#include <string>
#include <android/log.h>

#include <lc3.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

//定义TAG之后，我们可以在LogCat通过TAG过滤出NDK打印的日志
#define TAG "JNITEST"
// 定义info信息
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG,__VA_ARGS__)
// 定义debug信息
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
// 定义error信息
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG,__VA_ARGS__)

int test() {
    //PCM格式
    enum lc3_pcm_format pcmFormat = LC3_PCM_FORMAT_S16;
    //帧长10ms
    int dtUs = 10000;
    //采样率48K
    int srHz = 48000;
    //单帧编码后输出字节数
    uint16_t output_byte_count = 120;
    //编码器需占用缓存大小
    unsigned encodeSize = lc3_encoder_size(dtUs, srHz);
    //解码器需占用缓存大小
    unsigned decodeSize = lc3_decoder_size(dtUs, srHz);
    //单帧的采样数
    uint16_t sampleOfFrames = lc3_frame_samples(dtUs, srHz);
    //单帧字节数，16Bits下一个采样占用两个字节
    uint16_t bytesOfFrames = sampleOfFrames * 2;
    //编码器缓存
    void *encMem = NULL;
    //解码器缓存
    void *decMem = NULL;
    //输入文件的文件描述符
    int inFd = -1;
    //输出文件的文件描述符
    int outFd = -1;
    //输入帧缓冲
    unsigned char *inBuf = (unsigned char *) malloc(bytesOfFrames);
    //输出帧缓冲
    unsigned char *outBuf = (unsigned char *) malloc(bytesOfFrames);
    encMem = malloc(encodeSize);
    /*                      编码                           */
    lc3_encoder_t lc3_encoder = lc3_setup_encoder(dtUs, srHz, 0, encMem);
    if ((inFd = open("./test_48K_16.pcm", O_RDONLY)) <= 0) {
        LOGI("encode open inFd err\n");
        return -1;
    }
    if ((outFd = open("./encodedata", O_CREAT | O_WRONLY | O_TRUNC, 0666)) <= 0) {
        LOGE("encode open outFd err\n");
        return -1;
    }
    while (read(inFd, inBuf, bytesOfFrames) == bytesOfFrames) {
        lc3_encode(lc3_encoder, pcmFormat, (const int16_t *) inBuf, 1, output_byte_count, outBuf);
        // memcpy(outBuf,inBuf,bytesOfFrames);
        if (write(outFd, outBuf, output_byte_count) != output_byte_count) {
            LOGE("encode write err\n");
            break;
        }
        memset(inBuf, 0, bytesOfFrames);
        memset(outBuf, 0, bytesOfFrames);
    }
    free(encMem);
    encMem = NULL;
    close(inFd);
    close(outFd);
    /*                      解码                           */
    decMem = malloc(decodeSize);
    lc3_decoder_t lc3_decoder = lc3_setup_decoder(dtUs, srHz, 0, decMem);
    if ((inFd = open("./encodedata", O_RDONLY)) <= 0) {
        LOGE("decode open inFd err\n");
        return -1;
    }
    if ((outFd = open("./decode.pcm", O_CREAT | O_WRONLY | O_TRUNC, 0666)) <= 0) {
        LOGE("decode open outFd err\n");
        return -1;
    }
    while (read(inFd, inBuf, output_byte_count) == output_byte_count) {
        lc3_decode(lc3_decoder, inBuf, output_byte_count, pcmFormat, outBuf, 1);
        if (write(outFd, outBuf, bytesOfFrames) != bytesOfFrames) {
            LOGE("decode write err\n");
            break;
        }
        memset(inBuf, 0, bytesOfFrames);
        memset(outBuf, 0, bytesOfFrames);
    }
    free(decMem);
    close(inFd);
    close(outFd);
    free(inBuf);
    free(outBuf);
    inBuf = NULL;
    outBuf = NULL;
    return 0;
}

extern "C" JNIEXPORT jstring JNICALL
Java_com_mi_audio_lc3codec_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}


extern "C"
JNIEXPORT int JNICALL
Java_com_mi_audio_lc3codec_MainActivity_encode(JNIEnv *env, jobject thiz, jstring in_path,
                                          jstring out_path) {
    const char *nativeInPath = env->GetStringUTFChars(in_path, 0);
    const char *nativeOutPath = env->GetStringUTFChars(out_path, 0);

    //PCM格式
    enum lc3_pcm_format pcmFormat = LC3_PCM_FORMAT_S16;
    //帧长10ms
    int dtUs = 10000;
    //采样率48K
    int srHz = 48000;
    //单帧编码后输出字节数
    uint16_t output_byte_count = 120;
    //编码器需占用缓存大小
    unsigned encodeSize = lc3_encoder_size(dtUs, srHz);
    //单帧的采样数
    uint16_t sampleOfFrames = lc3_frame_samples(dtUs, srHz);
    //单帧字节数，16Bits下一个采样占用两个字节
    uint16_t bytesOfFrames = sampleOfFrames * 2;
    //编码器缓存
    void *encMem = NULL;
    //输入文件的文件描述符
    int inFd = -1;
    //输出文件的文件描述符
    int outFd = -1;
    //输入帧缓冲
    unsigned char *inBuf = (unsigned char *) malloc(bytesOfFrames);
    //输出帧缓冲
    unsigned char *outBuf = (unsigned char *) malloc(bytesOfFrames);
    encMem = malloc(encodeSize);
    /*                      编码                           */
    lc3_encoder_t lc3_encoder = lc3_setup_encoder(dtUs, srHz, 0, encMem);
    if ((inFd = open(nativeInPath, O_RDONLY)) <= 0) {
        LOGE("encode open inFd err\n");
        return -1;
    }
    if ((outFd = open(nativeOutPath, O_CREAT | O_WRONLY | O_TRUNC, 0666)) <= 0) {
        LOGE("encode open outFd err\n");
        return -1;
    }
    while (read(inFd, inBuf, bytesOfFrames) == bytesOfFrames) {
        lc3_encode(lc3_encoder, pcmFormat, (const int16_t *) inBuf, 1, output_byte_count, outBuf);
        // memcpy(outBuf,inBuf,bytesOfFrames);
        if (write(outFd, outBuf, output_byte_count) != output_byte_count) {
            LOGE("encode write err\n");
            break;
        }
        memset(inBuf, 0, bytesOfFrames);
        memset(outBuf, 0, bytesOfFrames);
    }
    free(encMem);
    encMem = NULL;
    close(inFd);
    close(outFd);

    free(inBuf);
    free(outBuf);
    inBuf = NULL;
    outBuf = NULL;
    return 0;
}

lc3_encoder_t lc3_encoder;

lc3_decoder_t lc3_decoder;

uint16_t output_byte_count = 120; // 单帧编码后输出字节数, 单位byte
int dtUs = 10000; //帧长10ms，单位微秒
int srHz  = 48000; // 采样率 48k
//编码器缓存
void *encMem = NULL;

//解码器缓存
void *decMem = NULL;


extern "C"
JNIEXPORT jint JNICALL
Java_com_mi_audio_lc3codec_LC3Encoder_createEncoder(JNIEnv *env, jobject thiz, jint frame_size,
                                             jint frame_duration, jint sample_rate) {
    output_byte_count = frame_size;
    
    //帧长10ms
    if (frame_duration) {
        dtUs = frame_duration;
    }
    //采样率48K
    if (sample_rate) {
        srHz = sample_rate;
    }
    //编码器需占用缓存大小
    unsigned encodeSize = lc3_encoder_size(dtUs, srHz);
   
    encMem = malloc(encodeSize);
    /*                      编码                           */
    lc3_encoder = lc3_setup_encoder(dtUs, srHz, 0, encMem);

    return 0;
}


extern "C"
JNIEXPORT jint JNICALL
Java_com_mi_audio_lc3codec_LC3Decoder_createDecoder(JNIEnv *env, jobject thiz, jint frame_size,
                                               jint frame_duration, jint sample_rate) {
    output_byte_count = frame_size;

    //帧长10ms
    if (frame_duration) {
        dtUs = frame_duration;
    }
    //采样率48K
    if (sample_rate) {
        srHz = sample_rate;
    }

    //解码器需占用缓存大小
    unsigned decodeSize = lc3_decoder_size(dtUs, srHz);
    decMem = malloc(decodeSize);
    
    lc3_decoder = lc3_setup_decoder(dtUs, srHz, 0, decMem);

    return 0;
}


extern "C"
JNIEXPORT jint JNICALL
Java_com_mi_audio_lc3codec_LC3Encoder_sampleOfFrames(JNIEnv *env, jobject thiz, jint frame_duration,
                                              jint sample_rate) {
    return    lc3_frame_samples(dtUs, srHz);
}

extern "C"
JNIEXPORT jint JNICALL
Java_com_mi_audio_lc3codec_LC3Decoder_sampleOfFrames(JNIEnv *env, jobject thiz, jint frame_duration,
                                                jint sample_rate) {
    return    lc3_frame_samples(dtUs, srHz);
}


extern "C"
JNIEXPORT jint JNICALL
Java_com_mi_audio_lc3codec_LC3Encoder_encode(JNIEnv *env, jobject thiz, jbyteArray src, jbyteArray dest) {
    if(lc3_encoder){
        //PCM格式
        enum lc3_pcm_format pcmFormat = LC3_PCM_FORMAT_S16;
        uint16_t sampleOfFrames = lc3_frame_samples(dtUs, srHz);
        //单帧字节数，16Bits下一个采样占用两个字节
        uint16_t bytesOfFrames = sampleOfFrames * 2;
        //输入帧缓冲
        unsigned char *inBuf = (unsigned char *) malloc(bytesOfFrames);
        //输出帧缓冲
        unsigned char *outBuf = (unsigned char *) malloc(bytesOfFrames);
        lc3_encode(lc3_encoder, pcmFormat, (const int16_t *) inBuf, 1, output_byte_count, outBuf);
        
    }
    
    return 0;
}

extern "C"
JNIEXPORT jbyteArray JNICALL
Java_com_mi_audio_lc3codec_LC3Decoder_decode(JNIEnv *env, jobject thiz, jbyteArray src) {

    LOGE("jni decode start");
    if(lc3_decoder){
        //PCM格式
        enum lc3_pcm_format pcmFormat = LC3_PCM_FORMAT_S16;
        uint16_t sampleOfFrames = lc3_frame_samples(dtUs, srHz);
        //单帧字节数，16Bits下一个采样占用两个字节
        uint16_t bytesOfFrames = sampleOfFrames * 2;

        //输入帧缓冲
        unsigned char *inBuf = (unsigned char *) malloc(bytesOfFrames);
        
        int len = env->GetArrayLength(src);
        env->GetByteArrayRegion(src, 0, len, reinterpret_cast<jbyte *>(inBuf));
       
        //输出帧缓冲
        unsigned char *outBuf = (unsigned char *) malloc(bytesOfFrames);
        lc3_decode(lc3_decoder, inBuf, output_byte_count, pcmFormat, outBuf, 1);

        LOGE("inBuf size = %d",strlen(reinterpret_cast<const char *const>(inBuf)) );
        LOGE("outBuf size = %d", strlen(reinterpret_cast<const char *const>(outBuf)));
        jbyteArray result = env->NewByteArray(bytesOfFrames);
        env->SetByteArrayRegion(result, 0, bytesOfFrames, reinterpret_cast<const jbyte *>(outBuf));
        
        return result;
        

//        while (read(inFd, inBuf, output_byte_count) == output_byte_count) {
//            lc3_decode(lc3_decoder, inBuf, output_byte_count, pcmFormat, outBuf, 1);
//            if (write(outFd, outBuf, bytesOfFrames) != bytesOfFrames) {
//                LOGE("decode write err\n");
//                break;
//            }
//            memset(inBuf, 0, bytesOfFrames);
//            memset(outBuf, 0, bytesOfFrames);
//        }

    }

    return 0;
}


extern "C"
JNIEXPORT void JNICALL
Java_com_mi_audio_lc3codec_LC3Encoder_destroyEncoder(JNIEnv *env, jobject thiz) {
    free(encMem);
    encMem = NULL;
}

extern "C"
JNIEXPORT void JNICALL
Java_com_mi_audio_lc3codec_LC3Decoder_destroyDecoder(JNIEnv *env, jobject thiz) {
    free(decMem);
    decMem = NULL;
}
extern "C"
JNIEXPORT jint JNICALL
Java_com_mi_audio_lc3codec_LC3Encoder_encodeFile(JNIEnv *env, jobject thiz, jstring input,
                                          jstring output) {
    const char *nativeInPath = env->GetStringUTFChars(input, 0);
    const char *nativeOutPath = env->GetStringUTFChars(output, 0);

    //PCM格式
    enum lc3_pcm_format pcmFormat = LC3_PCM_FORMAT_S16;
    //编码器需占用缓存大小
    unsigned encodeSize = lc3_encoder_size(dtUs, srHz);
    //单帧的采样数
    uint16_t sampleOfFrames = lc3_frame_samples(dtUs, srHz);
    //单帧字节数，16Bits下一个采样占用两个字节
    uint16_t bytesOfFrames = sampleOfFrames * 2;
    //编码器缓存
    void *encMem = NULL;
    //输入文件的文件描述符
    int inFd = -1;
    //输出文件的文件描述符
    int outFd = -1;
    //输入帧缓冲
    unsigned char *inBuf = (unsigned char *) malloc(bytesOfFrames);
    //输出帧缓冲
    unsigned char *outBuf = (unsigned char *) malloc(bytesOfFrames);
    encMem = malloc(encodeSize);
    /*                      编码                           */
    lc3_encoder_t lc3_encoder = lc3_setup_encoder(dtUs, srHz, 0, encMem);
    if ((inFd = open(nativeInPath, O_RDONLY)) <= 0) {
        LOGE("encode open inFd err\n");
        return -1;
    }
    if ((outFd = open(nativeOutPath, O_CREAT | O_WRONLY | O_TRUNC, 0666)) <= 0) {
        LOGE("encode open outFd err\n");
        return -1;
    }
    while (read(inFd, inBuf, bytesOfFrames) == bytesOfFrames) {
        lc3_encode(lc3_encoder, pcmFormat, (const int16_t *) inBuf, 1, output_byte_count, outBuf);
        // memcpy(outBuf,inBuf,bytesOfFrames);
        if (write(outFd, outBuf, output_byte_count) != output_byte_count) {
            LOGE("encode write err\n");
            break;
        }
        memset(inBuf, 0, bytesOfFrames);
        memset(outBuf, 0, bytesOfFrames);
    }
    free(encMem);
    encMem = NULL;
    close(inFd);
    close(outFd);

    free(inBuf);
    free(outBuf);
    inBuf = NULL;
    outBuf = NULL;
    return 0;
}
extern "C"
JNIEXPORT jint JNICALL
Java_com_mi_audio_lc3codec_LC3Decoder_decodeFile(JNIEnv *env, jobject thiz, jstring input,
                                          jstring output) {
    LOGE("start decode");
    const char *nativeInPath = env->GetStringUTFChars(input, 0);
    const char *nativeOutPath = env->GetStringUTFChars(output, 0);
    //PCM格式
    enum lc3_pcm_format pcmFormat = LC3_PCM_FORMAT_S16;
    //解码器需占用缓存大小
    unsigned decodeSize = lc3_decoder_size(dtUs, srHz);
    //单帧的采样数
    uint16_t sampleOfFrames = lc3_frame_samples(dtUs, srHz);
    //单帧字节数，16Bits下一个采样占用两个字节
    uint16_t bytesOfFrames = sampleOfFrames * 2;
    
    //输入文件的文件描述符
    int inFd = -1;
    //输出文件的文件描述符
    int outFd = -1;
    //输入帧缓冲
    unsigned char *inBuf = (unsigned char *) malloc(bytesOfFrames);
    //输出帧缓冲
    unsigned char *outBuf = (unsigned char *) malloc(bytesOfFrames);
    
    /*                      解码                           */
    decMem = malloc(decodeSize);
    lc3_decoder_t lc3_decoder = lc3_setup_decoder(dtUs, srHz, 0, decMem);
    if ((inFd = open(nativeInPath, O_RDONLY)) <= 0) {
        LOGE("decode open inFd err\n");
        return -1;
    }
    if ((outFd = open(nativeOutPath, O_CREAT | O_WRONLY | O_TRUNC, 0666)) <= 0) {
        LOGE("decode open outFd err\n");
        return -1;
    }
    while (read(inFd, inBuf, output_byte_count) == output_byte_count) {
        lc3_decode(lc3_decoder, inBuf, output_byte_count, pcmFormat, outBuf, 1);
        if (write(outFd, outBuf, bytesOfFrames) != bytesOfFrames) {
            LOGE("decode write err\n");
            break;
        }
        LOGE("inBuf size = %d",strlen(reinterpret_cast<const char *const>(inBuf)) );
        LOGE("outBuf size = %d", strlen(reinterpret_cast<const char *const>(outBuf)));
       
        memset(inBuf, 0, bytesOfFrames);
        memset(outBuf, 0, bytesOfFrames);
    }
    free(decMem);
    close(inFd);
    close(outFd);
    free(inBuf);
    free(outBuf);
    inBuf = NULL;
    outBuf = NULL;
    LOGE("end decode");
    return 0;
}

